﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Windows.Forms;
using AMS.Common;

namespace AMS.Configuration
{
    /// <summary>
    /// 一个用于根据配置转换ConfigData的类
    /// </summary>
    public class ListConfigData
    {
        /// <summary>
        /// 一个用于根据配置转换ConfigData的类
        /// </summary>
        /// <param name="config"></param>
        /// <param name="data"></param>
        public ListConfigData(ListConfigInfo config, object data)
        {
            this.config = config;
            this.data = data;
        }

        #region 字段和属性
        private ListConfigInfo config;
        private object data;
        /// <summary>
        /// 获取或设置配置信息
        /// </summary>
        public ListConfigInfo Config
        {
            get { return config; }
            set { config = value; }
        }

        /// <summary>
        /// 获取或设置数据源
        /// </summary>
        public object DataSource
        {
            get { return data; }
            set { data = value; }
        }
        #endregion

        #region Public方法
        /// <summary>
        /// 转换显示的数据
        /// </summary>
        /// <param name="callback"></param>
        public void ConvertDisplayData(Action<ConvertCallbackInfo> callback)
        {
            ConvertDisplayData(callback, null);
        }

        /// <summary>
        /// 转换显示的数据
        /// </summary>
        /// <param name="columns">要转换的列</param>
        public void ConvertDisplayData(Action<ConvertCallbackInfo> callback, string []columnNames)
        {
            if (config == null)
            {
                throw new ArgumentException("config");
            }
            if (data == null)
            {
                return;
            }

            if (data is DataTable)
            {
                ConvertDataTable(callback, (DataTable)data, GetColumns(config.DisplayColumns, columnNames));
            }
            else if (data is IEnumerable)
            {
                ConvertEnuerable(callback, (IEnumerable)data, GetColumns(config.DisplayColumns, columnNames));
            }
            else
            {
                throw new NotSupportedException(LocaleFramework.GetString("@CannotConvertDataOfUnnamedType"));
            }
        }

        /// <summary>
        /// 转换显示的数据为DataTable
        /// </summary>
        /// <returns></returns>
        public DataTable ConvertDisplayData()
        {
            string[] nulls = null;
            return ConvertDisplayData(nulls);
        }

        /// <summary>
        /// 转换显示的数据为DataTable
        /// </summary>
        /// <param name="columnNames"></param>
        /// <returns></returns>
        public DataTable ConvertDisplayData(string[] columnNames)
        {
            DataTable dt = config.CreateDisplayColumnTable(columnNames);
            DataRow row = null;
            ConvertDisplayData(new Action<ConvertCallbackInfo>(delegate(ConvertCallbackInfo callbackInfo)
                {
                    if (callbackInfo.IsRowChanged)
                    {
                        row = dt.NewRow();
                        dt.Rows.Add(row);
                    }

                    row[callbackInfo.ColumnIndex] = callbackInfo.Value;
                }), columnNames);

            return dt;
        }

        /// <summary>
        /// 转换导出的数据为DataTable
        /// </summary>
        /// <returns></returns>
        public DataTable ConvertExportData()
        {
            string[] nulls = null;
            return ConvertExportData(nulls);
        }

        /// <summary>
        /// 转换导出的数据为DataTable
        /// </summary>
        /// <param name="columnNames"></param>
        /// <returns></returns>
        /// <exception cref="NotSupportedException"></exception>
        public DataTable ConvertExportData(string[] columnNames)
        {
            DataTable dt = config.CreateExportColumnTable(columnNames);
            DataRow row = null;
            ConvertExportData(new Action<ConvertCallbackInfo>(delegate(ConvertCallbackInfo callbackInfo)
            {
                if (callbackInfo.IsRowChanged)
                {
                    row = dt.NewRow();
                    dt.Rows.Add(row);
                }

                row[callbackInfo.ColumnIndex] = callbackInfo.Value;
            }), columnNames);

            return dt;
        }

        /// <summary>
        /// 转换导出的数据
        /// </summary>
        /// <param name="callback"></param>
        public void ConvertExportData(Action<ConvertCallbackInfo> callback)
        {
            ConvertExportData(callback, null);
        }

        /// <summary>
        /// 转换导出的数据
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="columnNames">要转换的列</param>
        /// <exception cref="NotSupportedException">不支持的数据类型</exception>
        public void ConvertExportData(Action<ConvertCallbackInfo> callback, string[] columnNames)
        {
            if (config == null)
            {
                throw new ArgumentException("config");
            }
            if (data == null)
            {
                return;
            }

            if (data is DataTable)
            {
                ConvertDataTable(callback, (DataTable)data, GetColumns(config.ExportColumns, columnNames));
            }
            else if (data is IEnumerable)
            {
                ConvertEnuerable(callback, (IEnumerable)data, GetColumns(config.ExportColumns, columnNames));
            }
            else
            {
                throw new NotSupportedException(LocaleFramework.GetString("@CannotConvertDataOfUnnamedType"));
            }
        }
        #endregion

        #region Private方法
        /// <summary>
        /// 获取选中的列
        /// </summary>
        /// <param name="source"></param>
        /// <param name="columnNames"></param>
        /// <returns></returns>
        private List<ColumnInfo> GetColumns(List<ColumnInfo> source, string []columnNames)
        {
            if (columnNames == null || columnNames.Length == 0)
            {
                return source;
            }

            Dictionary<string, ColumnInfo> nameToColumn = new Dictionary<string, ColumnInfo>();
            foreach (ColumnInfo column in source)
            {
                nameToColumn.Add(column.Name, column);
            }

            List<ColumnInfo> dest = new List<ColumnInfo>();
            foreach (string name in columnNames)
            {
                dest.Add(nameToColumn[name]);
            }

            return dest;
        }

        private void ConvertDataTable(Action<ConvertCallbackInfo> callback, DataTable dataSource, List<ColumnInfo> columns)
        {
            // 将DataTable的列名与列索引建立起映射关系，避免使用列名去索引
            Dictionary<string, int> columnNameToIndex = new Dictionary<string, int>();
            for (int i = 0; i < dataSource.Columns.Count; i++)
            {
                columnNameToIndex.Add(dataSource.Columns[i].ColumnName, i);
            }

            ConvertCallbackInfo callbackInfo = new ConvertCallbackInfo();
            // 建立起显示的列名和列信息的映射
            // TODO: need chnage this function
            for (int i = 0; i < dataSource.Rows.Count; i++)
            {
                DataRow dataRow = dataSource.Rows[i];
                callbackInfo.IsRowChanged = true;
                for (int j = 0; j < columns.Count; j++)
                {
                    if (columns[j] is CompoundColumnInfo)
                    {
                        // 组合列
                        CompoundColumnInfo compoundColumn = columns[j] as CompoundColumnInfo;
                        if (compoundColumn.Columns.Length == 0)
                        {
                            callbackInfo.Set(j, columns[j], compoundColumn.Format);
                            callback(callbackInfo);
                            continue;
                        }

                        // 获取每个子列的值，然后使用string.Format()构造成出新的组合值
                        string[] subValues = new string[compoundColumn.Columns.Length];
                        for (int k = 0; k < compoundColumn.Columns.Length; k++)
                        {
                            ColumnInfo subColumn = compoundColumn.Columns[k];
                            int columnIndex = columnNameToIndex[subColumn.Name];
                            if (subColumn.DictKey > 0)
                            {
                                string dictSubKey;
                                if (dataRow[columnIndex].GetType() == typeof(bool))
                                {
                                    dictSubKey = (bool)dataRow[columnIndex] ? "1" : "0";
                                }
                                else
                                {
                                    dictSubKey = Convert.ToString(dataRow[columnIndex]);
                                }

                                subValues[k] = Dict.Instance.GetDictValue(subColumn.DictKey, dictSubKey);
                            }
                            else
                            {
                                subValues[k] = Convert.ToString(dataRow[columnIndex]);
                            }
                        }

                        callbackInfo.Set(j, columns[j], string.Format(compoundColumn.Format, subValues));
                        callback(callbackInfo);
                    }
                    else
                    {
                        // 简单列
                        int columnIndex = columnNameToIndex[columns[j].Name];
                        if (dataRow[columnIndex] == null || dataRow[columnIndex] == DBNull.Value)
                        {
                            callbackInfo.Set(j, columns[j], null);
                            callback(callbackInfo);
                            continue;
                        }

                        // 处理是否字典列
                        if (columns[j].DictKey > 0)
                        {
                            string dictSubKey;
                            if (dataRow[columnIndex].GetType() == typeof(bool))
                            {
                                dictSubKey = (bool)dataRow[columnIndex] ? "1" : "0";
                            }
                            else
                            {
                                dictSubKey = Convert.ToString(dataRow[columnIndex]);
                            }

                            callbackInfo.Set(j, columns[j], Dict.Instance.GetDictValue(columns[j].DictKey, dictSubKey));
                            callback(callbackInfo);
                        }
                        else
                        {
                            callbackInfo.Set(j, columns[j], Convert.ToString(dataRow[columnIndex]));
                            callback(callbackInfo);
                        }
                    }
                }
            }
        }

        private void ConvertEnuerable(Action<ConvertCallbackInfo> callback, IEnumerable dataSource, List<ColumnInfo> columns)
        {
            PropertyDescriptorCollection properties = ListBindingHelper.GetListItemProperties(dataSource);
            Dictionary<string, PropertyDescriptor> nameToProperty = new Dictionary<string, PropertyDescriptor>();
            for (int i = 0; i < properties.Count; i++)
            {
                nameToProperty.Add(properties[i].Name, properties[i]);
            }

            ConvertCallbackInfo callbackInfo = new ConvertCallbackInfo();
            IEnumerator ie = ((IEnumerable)dataSource).GetEnumerator();
            int index = -1;
            while (ie.MoveNext())
            {
                index++;
                callbackInfo.IsRowChanged = true;
                object rawData = ie.Current;
                for (int j = 0; j < columns.Count; j++)
                {
                    if (columns[j] is CompoundColumnInfo)
                    {
                        // 组合列
                        CompoundColumnInfo compoundColumn = columns[j] as CompoundColumnInfo;
                        if (compoundColumn.Columns.Length == 0)
                        {
                            callbackInfo.Set(j, columns[j], compoundColumn.Format);
                            callback(callbackInfo);
                            continue;
                        }

                        // 获取每个子列的值，然后使用string.Format()构造成出新的组合值
                        string[] subValues = new string[compoundColumn.Columns.Length];
                        for (int k = 0; k < compoundColumn.Columns.Length; k++)
                        {
                            ColumnInfo subColumn = compoundColumn.Columns[k];
                            PropertyDescriptor property = nameToProperty[subColumn.Name];
                            if (subColumn.DictKey > 0)
                            {
                                string dictSubKey = Convert.ToString(property.GetValue(rawData));
                                subValues[k] = Dict.Instance.GetDictValue(subColumn.DictKey, dictSubKey);
                            }
                            else
                            {
                                subValues[k] = Convert.ToString(property.GetValue(rawData));
                            }
                        }

                        callbackInfo.Set(j, columns[j], string.Format(compoundColumn.Format, subValues));
                        callback(callbackInfo);
                    }
                    else
                    {
                        // 简单列
                        if (!nameToProperty.ContainsKey(columns[j].Name))
                        {
                            continue;
                        }

                        PropertyDescriptor property = nameToProperty[columns[j].Name];
                        object ovalue = property.GetValue(rawData);
                        if (ovalue == null || ovalue == DBNull.Value)
                        {
                            callbackInfo.Set(j, columns[j], null);
                            callback(callbackInfo);
                            continue;
                        }

                        // 处理是否字典列
                        if (columns[j].DictKey > 0)
                        {
                            string dictSubKey = Convert.ToString(ovalue);
                            callbackInfo.Set(j, columns[j], Dict.Instance.GetDictValue(columns[j].DictKey, dictSubKey));
                            callback(callbackInfo);
                        }
                        else
                        {
                            callbackInfo.Set(j, columns[j], Convert.ToString(ovalue));
                            callback(callbackInfo);
                        }
                    }
                }
            }
        }
        #endregion
    }

}
